/**
 * MIT License
 * 
 * Copyright (c) 2024 - present @ ebraid
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef __EB_PLATFORM_H__
#define __EB_PLATFORM_H__


#include <kernel/device.h>
#include <kernel/driver.h>


/**
 * Platform bus type, it defined in platform.c file
 */
extern struct bus_type platform_bus;


/**
 * @brief Platform device structure
 * @device: Device structure
 * @io_base:  Device I/O base address
 * @private_data:  Device private data
 */
struct platform_device {
    struct device  device;
    size_t         io_base;
    void           *private_data;
};


/**
 * @brief Platform driver structure
 * @driver: Driver structure
 * @probe:  Device probe function
 * @remove:  Device remove function
 * @of_match_table:  Device match table
 */
struct platform_driver {
    struct driver driver;
    int (*probe)(struct platform_device *dev);
    void (*remove)(struct platform_device *dev);
};


#define  PLATFORM_SYSLOG_INFO(...)   SYSLOG_INFO("PLATFORM: "__VA_ARGS__)
#define  PLATFORM_SYSLOG_ERROR(...)  SYSLOG_ERROR("PLATFORM: "__VA_ARGS__)
#define  PLATFORM_SYSLOG_WARN(...)   SYSLOG_WARN("PLATFORM: "__VA_ARGS__)
#define  PLATFORM_DEBUG_TRACE(...)   DEBUG_TRACE("PLATFORM: "__VA_ARGS__)


#define platform_device_create_attr(pdev, name, data, len)  kobj_create_attr(&pdev->device.kobj, name, data, len)
#define platform_device_create_text_attr(pdev, name, text)  kobj_create_text_attr(&pdev->device.kobj, name, text);
#define platform_driver_create_attr(pdrv, name, data, len)  kobj_create_attr(&pdrv->driver.kobj, name, data, len)
#define platform_driver_create_text_attr(pdrv, name, text)  kobj_create_text_attr(&pdrv->driver.kobj, name, text);


#ifdef __cplusplus
extern "C" {
#endif


/**
 * @brief platform bus register
 * @return 0 on success, -1 on failure
 * @note this function must be called when system is initializing, before any platform device or drivers is registered
 */
int platform_bus_register(void);


/**
 * @brief Convert device to platform device
 * @param dev Device pointer
 * @return Platform device pointer
 * @note This function is used to convert device to platform device
 */
static inline struct platform_device* to_platform_device(struct device *dev)
{
    return container_of(dev, struct platform_device, device);
}


/**
 * @brief Convert driver to platform driver
 * @param drv Driver pointer
 * @return Platform driver pointer
 * @note This function is used to convert driver to platform driver
 */
static inline struct platform_driver* to_platform_driver(struct driver *drv)
{
    return container_of(drv, struct platform_driver, driver);
}


/**
 * @brief register an platform device
 * @param pdev Platform device pointer
 * @return The function returns zero on success or a negative error code on error
 * 
 */
static inline int platform_device_register(struct platform_device *pdev)
{
    pdev->device.bus = &platform_bus;
    return device_register(&pdev->device);
}


/**
 * @brief unregister an platform device
 * @param pdev Platform device pointer
 * @return none
 */
static inline void platform_device_unregister(struct platform_device *pdev)

{
    device_unregister(&pdev->device);
}


/**
 * @brief register an platform driver
 * @param pdrv Platform driver pointer
 * @return The function returns zero on success or a negative error code on error
 */
static inline int platform_driver_register(struct platform_driver *pdrv)
{
    pdrv->driver.bus = &platform_bus;
    return driver_register(&pdrv->driver);
}


/**
 * @brief unregister an platform driver
 * @param pdrv Platform driver pointer
 * @return none
 */
static inline void platform_driver_unregister(struct platform_driver *pdrv)
{
    driver_unregister(&pdrv->driver);
}


/**
 * @brief set driver data
 * @param pdev Platform device pointer
 * @param data Driver data
 * @return none
 */
static inline void platform_set_drvdata(struct platform_device *pdev, void *data)
{
    device_set_drvdata(&pdev->device, data);
}


/**
 * @brief get driver data
 * @param pdev Platform device pointer
 * @return Driver data
 */
static inline void* platform_get_drvdata(struct platform_device *pdev)
{
    return device_get_drvdata(&pdev->device);
}


/**
 * @brief set platform data
 * @param pdev Platform device pointer
 * @param data Platform data
 * @return none
 */
static inline void platform_set_platform_data(struct platform_device *pdev, const void *data)
{
    device_set_platform_data(&pdev->device, data);
}


/**
 * @brief get platform data
 * @param pdev Platform device pointer
 * @return Platform data
 */
static inline const void* platform_get_platform_data(struct platform_device *pdev)
{
    return device_get_platform_data(&pdev->device);
}


/**
 * @brief set platform data
 * @param pdev Platform device pointer
 * @param data Platform data
 * @return none
 */
static inline void platform_set_private_data(struct platform_device *pdev, void *data)
{
    pdev->private_data = data;
}


/**
 * @brief get platform data
 * @param pdev Platform device pointer
 * @return Platform data
 */
static inline void* platform_get_private_data(struct platform_device *pdev)
{
    return pdev->private_data;
}


#ifdef __cplusplus
}
#endif


#endif //!__EB_PLATFORM_H__